package com.example.teaching_server.service;

import com.example.teaching_server.config.FileUploadProperties;
import com.example.teaching_server.dto.FileUploadResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 文件上传服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class FileUploadService {

    private final FileUploadProperties fileUploadProperties;
    private static final long DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;

    /**
     * 上传文件
     */
    public FileUploadResponse uploadFile(MultipartFile file) {
        try {
            validateFile(file);
            validateFileType(file.getOriginalFilename());
            validateFileSize(file.getSize());

            String originalFileName = file.getOriginalFilename();
            String fileExtension = getFileExtension(originalFileName);
            String storageFileName = generateStorageFileName(fileExtension);
            String subDirectory = getFileSubDirectory(fileExtension);
            String storagePath = fileUploadProperties.getPath() + subDirectory;

            Path filePath = saveFileToDisk(file, storagePath, storageFileName);

            String relativeFilePath = subDirectory + "/" + storageFileName;
            String fileUrl = "/uploads" + relativeFilePath;

            return createSuccessResponse(storageFileName, relativeFilePath, fileUrl,
                    originalFileName, file.getSize(), getFileType(fileExtension));

        } catch (IllegalArgumentException e) {
            log.warn("文件上传参数错误: {}", e.getMessage());
            return FileUploadResponse.error(e.getMessage());
        } catch (IOException e) {
            log.error("文件上传IO错误", e);
            return FileUploadResponse.error("文件上传失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("文件上传系统错误", e);
            return FileUploadResponse.error("系统错误: " + e.getMessage());
        }
    }

    /**
     * 验证文件基本属性
     */
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
    }

    /**
     * 验证文件类型
     */
    private void validateFileType(String fileName) {
        if (!isAllowedFileType(fileName)) {
            throw new IllegalArgumentException("不支持的文件类型");
        }
    }

    /**
     * 验证文件大小
     */
    private void validateFileSize(long fileSize) {
        long maxFileSize = getMaxFileSize();
        if (fileSize > maxFileSize) {
            throw new IllegalArgumentException("文件大小超过限制（最大 " + formatFileSize(maxFileSize) + "）");
        }
    }

    /**
     * 保存文件到磁盘
     */
    private Path saveFileToDisk(MultipartFile file, String storagePath, String storageFileName) throws IOException {
        Path directory = Paths.get(storagePath);
        if (!Files.exists(directory)) {
            Files.createDirectories(directory);
        }

        Path filePath = directory.resolve(storageFileName);
        Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
        return filePath;
    }

    /**
     * 创建成功响应
     */
    private FileUploadResponse createSuccessResponse(String storageFileName, String relativeFilePath,
                                                     String fileUrl, String originalFileName,
                                                     long fileSize, String fileType) {
        return FileUploadResponse.success(storageFileName, relativeFilePath,
                fileUrl, originalFileName, fileSize, fileType);
    }

    /**
     * 检查文件类型是否允许
     */
    private boolean isAllowedFileType(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return false;
        }

        String extension = getFileExtension(fileName).toLowerCase();
        String allowedTypes = fileUploadProperties.getAllowedTypes();

        if (allowedTypes == null || allowedTypes.trim().isEmpty()) {
            return true;
        }

        String[] allowedTypeArray = allowedTypes.split(",");
        for (String allowedType : allowedTypeArray) {
            if (allowedType.trim().equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf(".");
        return lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1) : "";
    }

    /**
     * 生成存储文件名
     */
    private String generateStorageFileName(String extension) {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String randomId = UUID.randomUUID().toString().substring(0, 8);
        return timestamp + "_" + randomId + (extension.isEmpty() ? "" : "." + extension);
    }

    /**
     * 获取文件存储子目录
     */
    private String getFileSubDirectory(String extension) {
        String lowerExt = extension.toLowerCase();
        if (lowerExt.matches("jpg|jpeg|png|gif|bmp|webp")) {
            return getSafePath(fileUploadProperties.getImagePath());
        } else if (lowerExt.matches("mp4|avi|mov|wmv|flv|mkv")) {
            return getSafePath(fileUploadProperties.getVideoPath());
        } else {
            return getSafePath(fileUploadProperties.getDocumentPath());
        }
    }

    /**
     * 获取文件类型分类
     */
    private String getFileType(String extension) {
        String lowerExt = extension.toLowerCase();
        if (lowerExt.matches("jpg|jpeg|png|gif|bmp|webp")) {
            return "image";
        } else if (lowerExt.matches("mp4|avi|mov|wmv|flv|mkv")) {
            return "video";
        } else {
            return "document";
        }
    }

    /**
     * 确保路径安全
     */
    private String getSafePath(String path) {
        if (path == null || path.trim().isEmpty()) {
            return "/documents";
        }
        return path.startsWith("/") ? path : "/" + path;
    }

    /**
     * 获取最大文件大小
     */
    private long getMaxFileSize() {
        try {
            return parseFileSize(fileUploadProperties.getMaxSize());
        } catch (Exception e) {
            log.warn("文件大小配置解析失败，使用默认值10MB", e);
            return DEFAULT_MAX_FILE_SIZE;
        }
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(long size) {
        if (size < 1024) {
            return size + "B";
        } else if (size < 1024 * 1024) {
            return (size / 1024) + "KB";
        } else {
            return (size / (1024 * 1024)) + "MB";
        }
    }

    /**
     * 解析文件大小配置
     */
    private long parseFileSize(String sizeStr) {
        if (sizeStr == null || sizeStr.trim().isEmpty()) {
            return DEFAULT_MAX_FILE_SIZE;
        }

        try {
            String upperSizeStr = sizeStr.trim().toUpperCase();
            if (upperSizeStr.endsWith("MB")) {
                String numStr = upperSizeStr.substring(0, upperSizeStr.length() - 2).trim();
                return Long.parseLong(numStr) * 1024 * 1024;
            } else if (upperSizeStr.endsWith("KB")) {
                String numStr = upperSizeStr.substring(0, upperSizeStr.length() - 2).trim();
                return Long.parseLong(numStr) * 1024;
            } else {
                return Long.parseLong(upperSizeStr.trim());
            }
        } catch (NumberFormatException e) {
            log.warn("文件大小配置格式错误: {}, 使用默认值", sizeStr);
            return DEFAULT_MAX_FILE_SIZE;
        }
    }
}
